<?php
namespace App\Http\Controllers\Api\v1\Rabbitmq;

use App\Http\Controllers\Controller;
use App\Models\Api\Rectification as RectificationModel;
use App\Tools\Push;
use App\Tools\Rectification;
use DB;
use PhpAmqpLib\Connection\AMQPStreamConnection;

//error_reporting(0);
class RectificationController extends Controller
{

    public function stop($channel, $connection)
    {
        $channel->close();
        $connection->close();
    }

    public function start()
    {

        $connection = new AMQPStreamConnection(config('rabbitmq.host'), config('rabbitmq.port'), config('rabbitmq.username'), config('rabbitmq.password'));
        $channel    = $connection->channel();

        $channel->exchange_declare('delay_rectification_exchange', 'direct', false, false, false);
        $channel->exchange_declare('rectification_exchange', 'direct', false, false, false);

        $channel->queue_declare('delay_rectification_queue', false, true, false, false, false);
        $channel->queue_bind('delay_rectification_queue', 'delay_rectification_exchange', 'delay_rectification_exchange');

        print(' 监听Rabbitmq 生时校正消息队列... ');

        //只有consumer已经处理并确认了上一条message时queue才分派新的message给它
        $channel->basic_qos(null, 1, null);
        $channel->basic_consume('delay_rectification_queue', '', false, false, false, false, array($this, 'startRectificationTask'));

        register_shutdown_function(array($this, 'stop'), $channel, $connection);

        while (count($channel->callbacks)) {
            $channel->wait();
        }

    }

    public function startRectificationTask($msg)
    {

        print(date('Y-m-d H:i:s') . " [x] 接收到消息" . $msg->body);
        $data = json_decode($msg->body, true);

        print("生时校正开始时间 " . date('Y-m-d H:i:s') . "\n");

        // \think\Log::write('生时校正数据:'.var_export($data,true),'log',true);
        // 总共执行次数  最多120次（每分钟一个星盘）
        $n      = ceil($data['end_time'] - $data['start_time']) / 60;
        $events = [];
        for ($i = 0; $i < $n; $i++) {
            // 每分钟一个
            $birth_time                             = $data['start_time'] + $i * 60;
            $events[date('Y-m-d H:i', $birth_time)] = (new Rectification())->getValidEventsScore($data['events'], $birth_time, $data['recode']);
        }

        $events = array_filter($events);

        $reid = $data['reid'];

        $status     = 2;
        $result_all = [];

        if (empty($events)) {
            print("生时校正失败时间 " . date('Y-m-d H:i:s') . "\n");

            $status = 3;
        } else {
            array_multisort($events, SORT_NUMERIC, SORT_DESC);

            $result = array_slice($events, 0, 3, true);

            // 两个原则：1，优先接近用户原本时间的结果；
            // 2，优先与用户原上升星座相同的结果
            // 如果最高得分满足与原上升相同且在差距不超过十分钟这个条件，定位最佳结果，
            // 如果有多个，则最接近原时间的是最佳结果。
            // 如果最高得分不同时满足以上条件，优先在十分钟之内的，
            // 如没有则选择同上升的。同上升条件下选择更接近原时间的。

            // 统计各值在数组中出现的次数
            // $count_result = array_count_values($events);

            // \think\Log::write('生时校正结果统计:'. var_export($count_result,true),'log',true);

            $n = 0;
            foreach ($result as $k => $r) {
                if ($n == 1) {
                    $r--;
                } elseif ($n == 2) {
                    $r -= 2;
                }

                $result_all[] = ['time' => strtotime($k), 'score' => $r];
                $n++;
            }

            print("生时校正结果: " . var_export($result, true) . "\n");
//            \think\Log::write('任务执行次数:'.$job->attempts(),'log',true);
            //            print("任务执行次数：".$job->attempts()."\n");

            print("生时校正结束时间 " . date('Y-m-d H:i:s') . "\n");
        }

        try
        {
            $rectification = RectificationModel::findOrFail($reid);
            $rectification->update(['status' => $status, 'result_time' => time()]);

            if (!empty($result_all)) {
                $rectification->result()->where('reid', $reid)->delete(); // 先删再存
                $rectification->result()->insert($result_all);
            }
        } catch (\Exception $e) {
            print("生时校正结果入库失败 " . $e->getMessage() . "\n");

            $rectification = RectificationModel::findOrFail($reid);
            $rectification->update(['status' => 3]);

        }

        $user = User::where(['id' => $rectification['uid']])->first(['id', 'regid', 'tel'])->toArray();
        // APP推送
        if ($user && $user['regid'] != '') {
            print("开始推送:" . var_export($user, true) . "\n");

            (new Push())->pushSpecial($user['regid'], '您提交的生时校正已经完成了，点击查看校正结果！', ['action' => 'rectification_details', 'id' => $reid]);
        }
        // 短信通知
        if ($user && $user['tel'] != '') {
            print("短信通知:" . var_export($user, true) . "\n");
            sendSms($user['tel'], [], config('aliyun.dayu_rectification_code'));
        }
        //消息中心添加信息
        $data = [
            'range'       => $user['id'],
            'type'        => 2,
            'cid'         => 1,
            'reid'        => $reid,
            'title'       => '生时校正结果',
            'content'     => '您提交的生时校正已经完成了，点击查看校正结果！',
            'link'        => 'rectification_details?id=' . $reid,
            'target'      => "local",
            'create_time' => time(),
        ];
        DB::table('message_center')->insert($data);
        // else
        // {
        //     print("通知失败:" . var_export($user) ."\n");
        //
        // }
        //如果任务执行成功后 记得删除任务，不然这个任务会重复执行，直到达到最大重试次数后失败后，执行failed方法
        //        $job->delete();

        //确认收到消息
        $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
    }

}
